package com.hzmg.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.CharsetUtil;

public class SimpleServer {
    private static final MyFirstServerHandler myFirstServerHandler = new MyFirstServerHandler();

    public static void main(String[] args) throws Exception {
        //创建两个线程组 boosGroup,workerGroup Nio：非阻塞 一个用于接收客户端连接
        //一个用于对接收连接的客户端进行读写操作
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            //创建服务端启动器对象 ServerBootstrap:服务端启动器工厂类
            ServerBootstrap bootstrap = new ServerBootstrap();
            //将上面创建的两个线程组添加进服务端启动对象
            bootstrap.group(bossGroup, workerGroup)
                    //设置服务端通道实现类型，这里使用socket传输通道
                    .channel(NioServerSocketChannel.class)
                    //设置线程队列能得到的最大连接个数，该参数起限流作用，
                    //线程队列指第三次握手时的acept_queue队列
                    .option(ChannelOption.SO_BACKLOG, 128)
                    //设置保持活动连接状态
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    //使用匿名内部类的形式初始化通道对象
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            //给pipeline管道设置处理器,这个管道就是用来接收io传来的信息，并在里面进行处理,new TaskQueueDemo()
                            //socketChannel.pipeline().addLast(myFirstServerHandler);
                            ChannelPipeline pipeline=socketChannel.pipeline();
                            pipeline.addLast(new ScheduleTaskQueueDemo());
                        }
                    });//这里是给workerGroup的EventLoop对应的管道设置处理器
            System.out.println("[nettyDemo]:服务端准备就绪");
            //绑定端口号，启动服务端
            ChannelFuture channelFuture = bootstrap.bind(8888).sync();
            //对关闭通道进行监听
            channelFuture.channel().closeFuture().sync();
        } finally {
            //关闭队列组
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }


}

/**
 * 创建服务端处理器，
 * 自定义的Handler需要继承Netty规定好的HandlerAdapter
 * 才能被Netty框架所关联，类似SpringMVC的适配器模式
 */
class MyFirstServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //获取客户端发送过来的消息
        ByteBuf byteBuf = (ByteBuf) msg;
        System.out.println("[服务端]：收到客户端" + ctx.channel().remoteAddress() + "发送的消息: " + byteBuf.toString(CharsetUtil.UTF_8));
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        //解析完收到的消息后要回传给客户端
        ctx.writeAndFlush(Unpooled.copiedBuffer("服务端已收到消息", CharsetUtil.UTF_8));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        //异常捕获，以及对应处理，这里的处理为关闭通道
        ctx.close();
    }
}
